const TWO_TO_23 = 8388608
const TWO_TO_N149 = 1.401298464324817e-45

/** 二进制读取流 */
export default class BinaryReader {

    private static _pool: BinaryReader[] = []
    private _bytes: Uint8Array
    private _pos: number
    private _len: number

    private constructor() { }

    /** 从对象池里分配一个实例,如果池里没有则新建 */
    static alloc(bytes: Uint8Array) {
        let ins: BinaryReader = this._pool.pop() || new BinaryReader()
        ins._pos = 0
        ins._bytes = bytes
        ins._len = bytes.length
        return ins
    }

    /** 回收 */
    recy() {
        this._bytes = null
        BinaryReader._pool.push(this)
    }

    /** 往后切一段出来 */
    cut(len: number) {
        return this._bytes.slice(this._pos, this._pos += len)
    }

    get len() {
        return this._len
    }

    get hasNext() {
        return this._pos < this._len
    }

    get byte() {
        return this._bytes[this._pos++]
    }

    get uint8() {
        return this.byte
    }

    get uint16() {
        return this.byte | (this.byte << 8)
    }

    get uint32() {
        return (this.byte | (this.byte << 8) | (this.byte << 16) | (this.byte << 24)) >>> 0
    }

    /** 自适应长度uint32 */
    get uint() {
        let temp = this.byte
        let n = temp & 0x7F
        if (temp < 0x80) {
            return n
        }

        temp = this.byte
        n |= (temp & 0x7F) << 7
        if (temp < 0x80) {
            return n
        }

        temp = this.byte
        n |= (temp & 0x7F) << 14
        if (temp < 0x80) {
            return n
        }

        temp = this.byte
        n |= (temp & 0x7F) << 21
        if (temp < 0x80) {
            return n
        }

        temp = this.byte
        n |= (temp & 0x0F) << 28
        if (temp < 0x80) {
            return n >>> 0
        }

        return n
    }

    get int8() {
        return (this.byte << 24) >> 24
    }

    get int16() {
        return (((this.byte << 0) | (this.byte << 8)) << 16) >> 16
    }

    get int32() {
        return this.byte | (this.byte << 8) | (this.byte << 16) | (this.byte << 24)
    }

    /** 自适应长度int32 */
    get int() {
        let n = this.uint
        return (n >>> 1) ^ -(n & 1)
    }

    /** 32位浮点数，有精度差，要求精度数据应该使用整型乘精度再除回来 */
    get float() {
        let v = this.int32
        let sign = (v >> 31) * 2 + 1
        let exp = (v >>> 23) & 0xFF
        let mant = v & 0x7FFFFF

        if (exp == 0xFF) {
            return mant ? NaN : sign * Infinity
        }
        if (exp == 0) {
            return sign * TWO_TO_N149 * mant
        }
        return sign * Math.pow(2, exp - 150) * (mant + TWO_TO_23)
    }

    get str() {
        let str = ""
        let len = this.uint
        let end = this._pos + len
        let c: number
        let fn = String.fromCharCode
        while (this._pos < end) {
            c = this.byte
            if (c < 0x80) {
                str += fn(c)
            } else if (c < 0xe0) {
                str += fn(((c & 0x3F) << 6) | (this.byte & 0x7F))
            } else if (c < 0xF0) {
                str += fn(((c & 0x1F) << 12) | ((this.byte & 0x7F) << 6) | (this.byte & 0x7F))
            } else {
                str += fn(((c & 0x0F) << 18) | ((this.byte & 0x7F) << 12) | ((this.byte & 0x7F) << 6) | (this.byte & 0x7F))
            }
        }
        return str
    }

}